﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Web.Hosting;

// 编译之后的缓存问题

public class ZipVirtualDirectory : System.Web.Hosting.VirtualDirectory
{
    // 保存文件夹中包含的子项目的集合
    // 包括文件和子目录
    private List<VirtualFileBase> items;
    private List<VirtualFile> files;
    private List<VirtualDirectory> directories;
    private string name;

    public override System.Collections.IEnumerable Files
    {
        get
        {
            return this.files;
        }
    }
    public override System.Collections.IEnumerable Children
    {
        get
        {
            return this.items;
        }
    }

    public override System.Collections.IEnumerable Directories
    {
        get
        {
            return directories;
        }
    }

    public override string Name
    {
        get
        {
            return base.Name;
        }
    }

    public ZipVirtualDirectory(string name)
        : base(name)
    {
        this.items = new List<VirtualFileBase>();
        this.directories = new List<VirtualDirectory>();
        this.files = new List<VirtualFile>();

        this.name = name;
    }

    // 在目录中增加一个项目
    public void AddVirtualItem(VirtualFileBase item)
    {
        this.items.Add(item);
        if (item.IsDirectory)
            this.directories.Add(item as VirtualDirectory);
        else
            this.files.Add(item as VirtualFile);
    }
}

public class ZipVirtualFile : System.Web.Hosting.VirtualFile
{
    public override string Name
    {
        get
        {
            return this.name;
        }
    }

    public override System.IO.Stream Open()
    {
        return new System.IO.MemoryStream(this.buffer);
    }

    private string name;
    private byte[] buffer;

    public ZipVirtualFile(string name, byte[] buffer)
        : base(name)
    {
        this.name = name;
        this.buffer = buffer;
    }
}

public class ZipVirtualPathProvider : System.Web.Hosting.VirtualPathProvider
{
    private string fileRootPath;
    private string virtualRootPath;

    private ZipVirtualDirectory root;

    public ZipVirtualPathProvider()
    {
        this.fileRootPath = HttpRuntime.AppDomainAppPath;
        this.virtualRootPath = HttpRuntime.AppDomainAppVirtualPath + "/";

        string path = string.Format("{0}App_Data\\ZipSource.zip", fileRootPath);

        ICSharpCode.SharpZipLib.Zip.ZipFile zipFile
            = new ICSharpCode.SharpZipLib.Zip.ZipFile(path);

        // 创建根目录
        this.root = new ZipVirtualDirectory(virtualRootPath);

        foreach (ICSharpCode.SharpZipLib.Zip.ZipEntry entry in zipFile)
        {
            string name = string.Format("{0}{1}", this.virtualRootPath, entry.Name);

            VirtualDirectory parent = GetParentDirectory(name);
            ZipVirtualDirectory zipParent = parent as ZipVirtualDirectory;

            System.Web.Hosting.VirtualFileBase vfb;
            if (entry.IsDirectory)
            {
                vfb = new ZipVirtualDirectory(name);
            }
            else
            {
                System.IO.Stream stream = zipFile.GetInputStream(entry);
                int size = (int)entry.Size;
                byte[] buffer = ReadAllBytes(stream, size);
                vfb = new ZipVirtualFile(name, buffer);
            }
            zipParent.AddVirtualItem(vfb);
        }

        zipFile.Close();




    }

    // 寻找子目录所属的父目录 
    private VirtualDirectory GetParentDirectory(string virtualPath)
    {


        // 从根目录开始找，直到找不到为止，说明就是所属的父目录，加入父目录中
        VirtualDirectory root = this.root;
        while (true)
        {
            bool isContinue = false;
            foreach (VirtualDirectory dir in root.Directories)
            {
                if (virtualPath.StartsWith(dir.VirtualPath))
                {
                    root = dir;
                    isContinue = true;
                    break;
                }
            }

            if (isContinue)
                continue;

            // 如果都不是，那么，当前的  root 就是其父目录
            return root;
        }
    }


    public override bool DirectoryExists(string virtualDir)
    {
        /// 从根目录开始递归寻找
        bool result = SearchDirectory(this.root, virtualDir);
        if (result)
            return true;
        else
            return this.Previous.DirectoryExists(virtualDir);
    }

    private bool SearchDirectory(VirtualDirectory parent, string virtualDir)
    {
        if (parent.Name == virtualDir)
            return true;

        foreach (VirtualDirectory child in parent.Directories)
        {
            bool result = SearchDirectory(child, virtualDir);
            if (result)
                return true;

        }
        return false;
    }

    public override bool FileExists(string virtualPath)
    {
        /// 从根目录开始递归寻找
        bool result = SearchFile(this.root, virtualPath);
        if (result)
            return true;
        else
            return this.Previous.FileExists(virtualPath);
    }

    private bool SearchFile(VirtualDirectory parent, string virtualPath)
    {
        bool result = false;

        // 先查找当前目录
        foreach (VirtualFile file in parent.Files)
        {
            if (file.Name == virtualPath)
                return true;
        }

        // 再依次查找子目录
        foreach (VirtualDirectory child in parent.Directories)
        {
            result = SearchFile(child, virtualPath);
            if (result)
                return true;
        }

        // 都没有找到，返回假
        return false;
    }

    public override System.Web.Hosting.VirtualDirectory GetDirectory(string virtualDir)
    {
        VirtualDirectory dir = GetParentDirectory(virtualDir);

        // 不存在的话，找到父目录，存在的话，找到自己。
        bool exist = dir.VirtualPath == virtualDir;
        if (exist)
            return dir;
        else
            return this.Previous.GetDirectory(virtualDir);
    }

    public override System.Web.Hosting.VirtualFile GetFile(string virtualPath)
    {
        // 找到可能存在的目录
        VirtualDirectory dir = GetParentDirectory(virtualPath);

        // 遍历查找
        foreach (VirtualFile file in dir.Files)
        {
            if (file.VirtualPath == virtualPath)
                return file;
        }

        return this.Previous.GetFile(virtualPath);
    }

    public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
    {
        // 由于采用了压缩文件，所以不生成缓存依赖对象
        return null;
    }

    private byte[] ReadAllBytes(System.IO.Stream stream, int size)
    {
        byte[] buffer = new byte[size];

        int count = stream.Read(buffer, 0, size);
        return buffer;
    }
}


